﻿using System;
using System.Collections.Generic;
using SoundEngine3.AudioProcessing;
using SoundEngine3.DspPlugins;
using SoundEngine3.MIDI.Meta;
using ZquenceStudio3.Core;
using ZquenceStudio3.Core.DspPlugins;
using ZquenceStudio3.DspPlugins;
using ZquenceStudio3Host.DspPlugins.Synthesizers.Nodesizer.Engine.Modules.HighLevel;
using DefaultDspPluginsLib.Depricated;
using static ZquenceStudio.DefaultDspPlugins.Effects.Distortion;
using ZquenceStudio.DefaultDspPlugins.Effects;
using DefaultDspPlugins.Effects;

namespace DefaultDspPluginsLib.Synthesizers
{
    public class LayerDescription : IDspPlugin
    {
        public DspPluginInfo GetDspPluginInfo()
        {
            return new DspPluginInfo("_Benchmark", DspType.Synthesizer, true);
        }

        public BaseDspPluginInstance CreateDsp(ZquenceStudio3Context context, DspPluginInfo info)
        {
            return new BenchmarkDsp(context, info);
        }
    }

    class BenchmarkDsp : BaseDspPluginInstance, IBenchmarkDsp
    {
        #region Not used
        public override string PluginInfo { get { return DspPluginInfo.DefaultPluginInfo; } }

        public override Version Version { get { return DspPluginInfo.DefaultVersion; } }

        public override void ChangeBufferSize(int bufferSize)
        {

        }

        public override void ChangeInputChannels(int channels)
        {

        }

        public override void ChangeOutputChannels(int channels)
        {

        }

        public override void ChangeSampleRate(double sampleRate)
        {

        }

        public override BaseAudioBuffer OnProcessOutput()
        {
            throw new NotSupportedException();
        }

        public override void Process(BaseAudioBuffer input, BaseAudioBuffer output)
        {
            throw new NotSupportedException();
        }

        protected override void OnProcessEvents(List<MidiMessage> midiMessages)
        {
            throw new NotSupportedException();
        }
        #endregion

        ZquenceStudio3Context context;
        DspPluginInfo info;

        const int BUFFERSIZE = 1024;
        double[] Pitch;
        double[] Frequency;
        double[] Volyme;
        double[] Tune;
        double[] Waveform;
        double[] Output;
        double[] RunAndIdle;
        double[] buffer8;
        double variable1;
        double variable2;

        public BenchmarkDsp(ZquenceStudio3Context context, DspPluginInfo info) : base(context.SoundEngine.SoundEngineContext, info)
        {
            this.context = context;
            this.info = info;
            Pitch = new double[BUFFERSIZE];
            Frequency = new double[BUFFERSIZE];
            Volyme = new double[BUFFERSIZE];
            Tune = new double[BUFFERSIZE];
            Waveform = new double[BUFFERSIZE];
            Output = new double[BUFFERSIZE];
            RunAndIdle = new double[BUFFERSIZE];
            buffer8 = new double[BUFFERSIZE];
        }

        int sin_i;
        void WriteSinus(double[] buffer)
        {
            for (int i = 0; i < buffer.Length; i++)
            {
                buffer[i] = Math.Sin(sin_i++ * 0.001);
            }
        }
        void WriteRunAndIdle(double[] buffer)
        {
            bool on = false;
            for (int i = 0; i < buffer.Length; i++)
            {
                if (i % 100 == 0)
                {
                    on = !on;
                }
                if (on)
                {
                    buffer[i] = 1;
                }
                else
                {
                    buffer[i] = 0;
                }
            }
        }
        void WriteValue(double[] buffer, double value)
        {
            for (int i = 0; i < buffer.Length; i++)
            {
                buffer[i] = value;
            }
        }

        public BenchmarkTest Test { get; set; }

        public double RunTest(int count)
        {
            sin_i = 0;
            WriteValue(Pitch, 54);
            WriteValue(Frequency, 3000);
            WriteValue(Volyme, 0.8);
            WriteValue(Tune, 0.0);
            WriteSinus(Waveform);
            WriteSinus(Output);
            WriteRunAndIdle(RunAndIdle);
            WriteSinus(buffer8);
            variable1 = 0;
            variable2 = 44100;

            double start = SharpDepend.Manager.StopwatchManager.TickTime;

            switch (Test)
            {
                case BenchmarkTest.Oscilator_Cpp:
                    {
                        for (int i = 0; i < count; i++)
                        {
#if !Portable
                            OscilatorModule.Common_Modulizer_Oscilator_Process(BUFFERSIZE, BUFFERSIZE, ref variable1, Pitch, Frequency, Volyme, Tune, Waveform, Output, RunAndIdle, buffer8, variable2);
#else
                            return -1;
#endif
                        }
                    }
                    break;
                case BenchmarkTest.Oscilator_Cs:
                    {
                        for (int i = 0; i < count; i++)
                        {
                            Common_Modulizer_Oscilator.Process(BUFFERSIZE, BUFFERSIZE, ref variable1, Pitch, Frequency, Volyme, Tune, Waveform, Output, RunAndIdle, buffer8, variable2);
                        }
                    }
                    break;
                case BenchmarkTest.LFO_Cpp:
                    {
                        for (int i = 0; i < count; i++)
                        {
#if !Portable
                            LFOModule.Common_Modulizer_LFO_Process(BUFFERSIZE, BUFFERSIZE, ref variable1, 0, 0, 130, Tune, Volyme, Pitch, Waveform, Output, variable2);
#else
                            return -1;
#endif
                        }
                    }
                    break;
                case BenchmarkTest.LFO_Cs:
                    {
                        for (int i = 0; i < count; i++)
                        {
                            Common_Modulizer_LFO.Process(BUFFERSIZE, BUFFERSIZE, ref variable1, 0, 0, 130, Tune, Volyme, Pitch, Waveform, Output, variable2);
                        }
                    }
                    break;
                case BenchmarkTest.SideChaining_Cpp:
                    {
#if !Portable
                        IntPtr ptr = Sidechaining.Effect_SideChaining_Create();
                        Sidechaining.Effect_SideChaining_Setup(ptr, 1, 0.0999, 0.2, 0, 20353);
                        for (int i = 0; i < count; i++)
                        {
                            Sidechaining.Effect_SideChaining_Process(ptr, 0, BUFFERSIZE, Waveform, Waveform, Output, Output);
                        }
                        Sidechaining.Effect_SideChaining_Delete(ptr);
#else
                            return -1;
#endif
                    }
                    break;
                case BenchmarkTest.SideChaining_Cs:
                    {
                        Effect_SideChaining effect = new Effect_SideChaining();
                        effect.Setup(1, 0.0999, 0.2, 0, 20353);
                        for (int i = 0; i < count; i++)
                        {
                            effect.Process(0, Waveform, Waveform, Output, Output);
                        }
                    }
                    break;
                case BenchmarkTest.Distortion_Cpp:
                    {
                        DistortionData data;
                        data.Channels = 2;
                        data.Dist = 0.5;
                        data.Length = BUFFERSIZE;
                        data.Output = 0.5;
                        for (int i = 0; i < count; i++)
                        {
#if !Portable
                            Distortion.Effect_Distortion_Process(ref data, ref Pitch[0], ref Frequency[0], ref Volyme[0], ref Tune[0]);
#else
                            return -1;
#endif
                        }
                    }
                    break;
                case BenchmarkTest.Distortion_Cs:
                    {
                        DistortionData data;
                        data.Channels = 2;
                        data.Dist = 0.5;
                        data.Length = BUFFERSIZE;
                        data.Output = 0.5;
                        for (int i = 0; i < count; i++)
                        {
                            Effect_Distortion.Process(ref data, Pitch, Frequency, Volyme, Tune);
                        }
                    }
                    break;
                case BenchmarkTest.Reverb_Cpp:
                    {
                        Reverb.ReverbData data;
                        data.channels = 2;
                        data.Length = BUFFERSIZE;
#if !Portable
                        IntPtr ptr = Reverb.Effect_Reverb_Create();
                        for (int i = 0; i < count; i++)
                        {
                            Reverb.Effect_Reverb_Process(ptr, ref data, ref Pitch[0], ref Frequency[0], ref Volyme[0], ref Tune[0]);
                        }
                        Reverb.Effect_Reverb_Delete(ptr);
#else
                            return -1;
#endif
                    }
                    break;
                case BenchmarkTest.Reverb_Cs:
                    {
                        Effect_Reverb mReverbCs = new Effect_Reverb();
                        Reverb.ReverbData data;
                        data.channels = 2;
                        data.Length = BUFFERSIZE;
                        for (int i = 0; i < count; i++)
                        {
                            mReverbCs.Process(ref data, Pitch, Frequency, Volyme, Tune);
                        }
                    }
                    break;
                case BenchmarkTest.Compressor_Cpp:
                    {
                        Compressor.CompressorData data;
                        data.env = 0;
                        data.inputGain = 0.5;
                        data.n = BUFFERSIZE;
                        data.outputGain = 0.5;
                        data.slope = 0.5;
                        data.sr = 44100;
                        data.tatt = 0.5;
                        data.threshold = 0.5;
                        data.tla = 0.5;
                        data.trel = 0.5;
                        data.twnd = 0.5;
                        for (int i = 0; i < count; i++)
                        {
#if !Portable
                            Compressor.Effect_Compressor_Process(ref data, ref Waveform[0], ref Waveform[0], ref Output[0], ref Output[0]);
#else
                            return -1;
#endif
                        }
                    }
                    break;
                case BenchmarkTest.Compressor_Cs:
                    {
                        Compressor.CompressorData data;
                        data.env = 0;
                        data.inputGain = 0.5;
                        data.n = BUFFERSIZE;
                        data.outputGain = 0.5;
                        data.slope = 0.5;
                        data.sr = 44100;
                        data.tatt = 0.5;
                        data.threshold = 0.5;
                        data.tla = 0.5;
                        data.trel = 0.5;
                        data.twnd = 0.5;
                        for (int i = 0; i < count; i++)
                        {
                            DefaultDspPluginsLib.Depricated.Effect_Compressor.Process(ref data, Waveform, Waveform, Output, Output);
                        }
                    }
                    break;
                default:
                    break;
            }

            return SharpDepend.Manager.StopwatchManager.TickTime - start;
        }
    }
}
